<?php

/**
 * Db
 *
 * @copyright       Copyright (C) 2010-2012 ARESCMS Inc.
 * @author          TomQin <tomqin@gmail.com>
 * @license         http://www.arescms.cn/license/
 * @package Core
 */
class Db{
    private static $db;

    public static function instance($opts){
        if(!(self::$db && self::$db instanceof Db_Mysqli)){
            self::$db = new Db_Mysqli($opts);
            self::$db->reconnect();
        }
        return self::getInstance();
    }

    public static function table($name){
        if(strpos($name, '`') === false && strpos($name, '.') === false) {
            return "`{$name}`";
        } else {
            return $name;
        }
    }

    public static function getInstance(){
        return self::$db;
    }

    public static function query($sql) {
        return self::$db->query($sql);
    }

    public static function prepare($sql) {
        return self::$db->prepare($sql);
    }

    public static function getAll($sql) {
        $data = array();
        $result = self::$db->query($sql);
        while($row = $result->fetch_assoc()){
            $data[] = $row;
        }
        return $data;
    }

    public static function getKeyArray($sql, $key1, $key2 = '') {
        $data = array();
        $result = self::$db->query($sql);
        if($key1 && $key2){
            while($row = $result->fetch_assoc()){
                $data[$row[$key1]] = $row[$key2];
            }
        }else{
            while($row = $result->fetch_assoc()){
                $data[$row[$key1]] = $row;
            }
        }
        return $data;
    }

    public static function getFirst($sql) {
        $row = self::$db->query($sql)->fetch_row();
        return $row[0];
    }

    public static function getRow($sql) {
        return self::$db->query($sql)->fetch_assoc();
    }

    public static function escapeString($var){
        return self::$db->real_escape_string($var);
    }

    public static function affectedRows() {
        return self::$db->affected_rows;
    }

    public static function insertId() {
        return self::$db->insert_id;
    }

    public static function execute($sql) {
        self::$db->query($sql);
        return self::$db->affected_rows;
    }

    public static function insert($table, array $data, $replace = false){
        $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
        $sql = $cmd.' '.self::table($table).' SET';
        $comm = '';
        foreach($data as $key => $var){
            $sql .= $comm." `{$key}`=".(is_null($var) ? 'NULL' : "'".self::escapeString($var))."'";
            $comm = ',';
        }
        self::query($sql);
        return self::insertId();
    }

    public static function insertBatch($table, array $data, $replace = false){
        $fields = current($data);
        if(!is_array($fields)){
            $fields  = $data;
            $data = array(0 => $data);
        }

        $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
        $sql = $cmd.' '.self::table($table).' SET';
        $comm = $stype = '';
        foreach($fields as $key => $var){
            $sql   .= $comm." `{$key}`= ? ";
            $comm   = ',';
            $stype .= 's';
        }

        $stmt = self::$db->prepare($sql);
        foreach($data as $line){
            self::$db->stmt_bind_param($stmt, $stype, $line);
            $stmt->execute();
            $ret[] = self::$db->insert_id;
        }

        return $ret;
    }

    /*
     *
     * note: prepare not support mulit query mode (under win32)
     */
    public static function proc($sql, $result_type = MYSQLI_ASSOC) {

        $command = self::getCommand($sql);
        if (!in_array($command, array('CALL'))) {
            throw new Exception('Only CALL allowed via Db::proc().');
        }

        $result = self::$db->multi_query($sql);
        if (!$result && self::$db->errno) {
            throw new Exception('Unable to proc a sql.');
        } else if ($result) {
            $data = array();
            do {
                if ($result = self::$db->store_result()) {
                    $rowset = array();
                    while($row = $result->fetch_assoc()){
                        $rowset[] = $row;
                    }
                    $data[] = $rowset;
                    $result->free();
                }
            } while (self::$db->more_results() && self::$db->next_result());

            return $data;
        } else {
            return ture;
        }
    }

    public static function getCommand($sql) {
        $command = strtoupper(substr($sql, 0, strpos(trim($sql), ' ')));
        return $command;
    }
}
?>